#pragma once

#include "include_gl.h"
#include "GLBuffer.h"
#include "GLProgram.h"

class PCGSolver
{
	friend class PCGSolverTest;
public:
	PCGSolver();
	~PCGSolver();

	void set(GLBuffer* sparseMatrix, GLBuffer* nodeNeighborhood, GLBuffer* bVector, unsigned numNodes);
	void solve(GLBuffer* initialSolution, unsigned numIterations);

private:
	void matrixTimesVector(GLBuffer* vector, GLBuffer* solution);
	void scalarProduct(GLBuffer* vector1, GLBuffer* vector2, GLBuffer* solution, unsigned n);

	GLBuffer* _sparseMatrix;
	GLBuffer* _nodeNeighborhood;
	GLBuffer* _bVector;
	unsigned _numNodes;

	GLBuffer* _rBuffer, *_zBuffer, *_pBuffer, *_sBuffer;
	GLBuffer* _oneBuffer;

	GLBuffer* _scalarProductTempBuffer;

	GLProgram* _clearDataProgram;
	struct {
		GLint value;
		GLint n;
	} _clearDataProgramUL;

	GLProgram* _matrixTimesVectorProgram;
	struct {
		GLint numRows;
	} _matrixTimesVectorProgramUL;

	GLProgram* _pcgJacobiPreconditionProgram;
	struct {
		GLint numRows;
	} _pcgJacobiPreconditionProgramUL;

	GLProgram* _vectorAddProgram;
	struct {
		GLint scalarID;
		GLint numRows;
		GLint factor;
	} _vectorAddProgramUL;

	GLProgram* _scalarProduct1Program;
	struct {
		GLint n;
	} _scalarProduct1ProgramUL;

	GLProgram* _scalarProduct2Program;
	struct {
		GLint n;
		GLint outIndex;
		GLint extraTermIndex;
	} _scalarProduct2ProgramUL;
};